package com.example.proxy;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.annation.Param;

import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import java.util.logging.Logger;

/**
 * @Classname MethodProxy
 * @Description TODO
 * @Date 2023/4/24 15:27
 * @Created by XiongXiong
 * @Author: X.I.O
 */
public class MethodProxy {

    private Logger logger;

    private Class<?> clazz;

    private Object obj;

    private Method method;

    private Class<?>[] argsClass;

    private Map<String,ArgModel> mapArgModel;

    private List<ArgModel> argModels;

    private String requestMethod;

    public MethodProxy(Class<?> clazz, Method method,String requestMethod,Object obj) {
        this.clazz = clazz;
        this.method = method;
        this.obj=obj;
        this.logger=Logger.getLogger(clazz.getName());
        this.requestMethod=requestMethod;
        init();
    }

    private void init() {
        this.argsClass=this.method.getParameterTypes();
        this.mapArgModel=new HashMap<>();
        this.argModels = new ArrayList<>();
        Annotation[][] annotations=method.getParameterAnnotations();;
        for (int i = 0; i < argsClass.length; i++) {
            Annotation[] antionsArg=annotations[i];
            Param param=getAnnotationParams(antionsArg);
            Class<?> cls = argsClass[i];
            ArgModel argModel= new ArgModel();
            argModel.setCls(cls);
            argModel.setParam(false);
            argModel.setRequired(false);
            if(param != null){
                argModel.setParam(true);
                argModel.setDefaultValue(param.defalultValue());
                argModel.setRequired(param.required());
                argModel.setName(param.value());
                mapArgModel.put(param.value(),argModel);
            }
            argModels.add(argModel);
        }
    }


    private Param getAnnotationParams(Annotation[] annotations){
        if(annotations==null){
            return null;
        }
        for (Annotation annotation : annotations) {
            if(annotation instanceof Param){
                return (Param) annotation;
            }
        }
        return null;
    }

    /***
     * 执行
     * @param args
     * @return
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public Object execute(Object...args) throws InvocationTargetException, IllegalAccessException {
        try {
           Object val=null;
           if(args.length == 0){
               val=method.invoke(obj);
           }else {
               val=method.invoke(obj,args);
           }
           return val;
        }catch (Exception e1){
            e1.printStackTrace();
        }
        return null;
    }


    public Class<?> getClazz() {
        return clazz;
    }

    public void setClazz(Class<?> clazz) {
        this.clazz = clazz;
    }

    public Object getObj() {
        return obj;
    }

    public void setObj(Object obj) {
        this.obj = obj;
    }

    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }

    public class ArgModel{

        private String name;

        private Class<?> cls;

        private boolean isParam;

        private Object defaultValue;

        private boolean isRequired;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Class<?> getCls() {
            return cls;
        }

        public void setCls(Class<?> cls) {
            this.cls = cls;
        }

        public Object getDefaultValue() {
            return defaultValue;
        }

        public void setDefaultValue(Object defaultValue) {
            this.defaultValue = defaultValue;
        }

        public boolean isRequired() {
            return isRequired;
        }

        public void setRequired(boolean required) {
            isRequired = required;
        }

        public boolean isParam() {
            return isParam;
        }

        public void setParam(boolean param) {
            isParam = param;
        }
    }

    public Class<?>[] getArgsClass() {
        return argsClass;
    }

    public void setArgsClass(Class<?>[] argsClass) {
        this.argsClass = argsClass;
    }

    public Map<String, ArgModel> getMapArgModel() {
        return mapArgModel;
    }

    public void setMapArgModel(Map<String, ArgModel> mapArgModel) {
        this.mapArgModel = mapArgModel;
    }

    public Logger getLogger(){
        return this.logger;
    }

    public void info(String msg){
        this.logger.info(msg);
    }


    public void info(Supplier<String> msgSupplier){
        this.logger.info(msgSupplier);
    }

    public List<ArgModel> getArgModels() {
        return argModels;
    }

    public void setArgModels(List<ArgModel> argModels) {
        this.argModels = argModels;
    }

    public String getRequestMethod() {
        return requestMethod;
    }

    public void setRequestMethod(String requestMethod) {
        this.requestMethod = requestMethod;
    }
}
